package mamba
//
//import (
//	"context"
//	"errors"
//	"fmt"
//	"net"
//
//	"strings"
//	"sync"
//
//	http "github.com/Danny-Dasilva/fhttp"
//	http2 "github.com/Danny-Dasilva/fhttp/http2"
//	utls "github.com/Danny-Dasilva/utls"
//	"golang.org/x/net/proxy"
//)
//
//var errProtocolNegotiated = errors.New("protocol negotiated")
//
//type RoundTripper struct {
//	sync.Mutex
//	// fix typing
//	JA3       string
//	UserAgent string
//
//	Cookies           []Cookie
//	cachedConnections map[string]net.Conn
//	cachedTransports  map[string]http.RoundTripper
//
//	Dialer proxy.ContextDialer
//}
//
//func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
//	// Fix this later for proper cookie parsing
//	//for _, properties := range rt.Cookies {
//	//	req.AddCookie(&http.Cookie{Name: properties.Name,
//	//		Value:      properties.Value,
//	//		Path:       properties.Path,
//	//		Domain:     properties.Domain,
//	//		Expires:    properties.JSONExpires.Time, //TODO: scuffed af
//	//		RawExpires: properties.RawExpires,
//	//		MaxAge:     properties.MaxAge,
//	//		HttpOnly:   properties.HTTPOnly,
//	//		Secure:     properties.Secure,
//	//		Raw:        properties.Raw,
//	//		Unparsed:   properties.Unparsed,
//	//	})
//	//}
//	req.Header.Set("User-Agent", rt.UserAgent)
//
//	addr := rt.getDialTLSAddr(req)
//	if _, ok := rt.cachedTransports[addr]; !ok {
//		if err := rt.getTransport(req, addr); err != nil {
//			return nil, err
//		}
//	}
//	return rt.cachedTransports[addr].RoundTrip(req)
//}
//
//func (rt *RoundTripper) getTransport(req *http.Request, addr string) error {
//	switch strings.ToLower(req.URL.Scheme) {
//	case "http":
//		rt.cachedTransports[addr] = &http.Transport{DialContext: rt.Dialer.DialContext, DisableKeepAlives: true}
//		return nil
//	case "https":
//	default:
//		return fmt.Errorf("invalid URL scheme: [%v]", req.URL.Scheme)
//	}
//
//	_, err := rt.dialTLS(context.Background(), "tcp", addr)
//	switch err {
//	case errProtocolNegotiated:
//	case nil:
//		// Should never happen.
//		panic("此域名从未单步请求过的，先请求一次主域名，然后再并发请求此域名下的其他链接，不能直接并发请求")
//		//panic("dialTLS returned no error when determining cachedTransports")
//	default:
//		return err
//	}
//
//	return nil
//}
//
//func (rt *RoundTripper) dialTLS(ctx context.Context, network, addr string) (net.Conn, error) {
//	rt.Lock()
//	defer rt.Unlock()
//
//	// If we have the connection from when we determined the HTTPS
//	// cachedTransports to use, return that.
//	if conn := rt.cachedConnections[addr]; conn != nil {
//		delete(rt.cachedConnections, addr)
//		return conn, nil
//	}
//
//	rawConn, err := rt.Dialer.DialContext(ctx, network, addr)
//	if err != nil {
//		return nil, err
//	}
//
//	var host string
//	if host, _, err = net.SplitHostPort(addr); err != nil {
//		host = addr
//	}
//	//////////////////
//
//	spec, err := StringToSpec(rt.JA3, rt.UserAgent)
//	if err != nil {
//		return nil, err
//	}
//
//	conn := utls.UClient(rawConn, &utls.Config{ServerName: host, InsecureSkipVerify: true}, // MinVersion:         tls.VersionTLS10,
//		// MaxVersion:         tls.VersionTLS13,
//
//		utls.HelloCustom)
//
//	if err := conn.ApplyPreset(spec); err != nil {
//		return nil, err
//	}
//
//	if err = conn.Handshake(); err != nil {
//		_ = conn.Close()
//
//		if err.Error() == "tls: CurvePreferences includes unsupported curve" {
//			//fix this
//			return nil, fmt.Errorf("conn.Handshake() error for tls 1.3 (please retry request): %+v", err)
//		}
//		return nil, fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
//	}
//
//	//////////
//	if rt.cachedTransports[addr] != nil {
//		return conn, nil
//	}
//
//	// No http.Transport constructed yet, create one based on the results
//	// of ALPN.
//	switch conn.ConnectionState().NegotiatedProtocol {
//	case http2.NextProtoTLS:
//		parsedUserAgent := parseUserAgent(rt.UserAgent)
//		t2 := http2.Transport{DialTLS: rt.dialTLSHTTP2,
//			PushHandler: &http2.DefaultPushHandler{},
//			Navigator:   parsedUserAgent}
//		t2.Settings = []http2.Setting{
//			{ID: http2.SettingMaxConcurrentStreams, Val: 1000},
//			{ID: http2.SettingMaxFrameSize, Val: 16384},
//			{ID: http2.SettingMaxHeaderListSize, Val: 262144},
//		}
//		t2.InitialWindowSize = 6291456
//		t2.HeaderTableSize = 65536
//		t2.PushHandler = &http2.DefaultPushHandler{}
//		rt.cachedTransports[addr] = &t2
//	default:
//		// Assume the remote peer is speaking HTTP 1.x + TLS.
//		rt.cachedTransports[addr] = &http.Transport{DialTLSContext: rt.dialTLS}
//
//	}
//
//	// Stash the connection just established for use servicing the
//	// actual request (should be near-immediate).
//
//	rt.cachedConnections[addr] = conn
//	return nil, errProtocolNegotiated
//}
//
//func (rt *RoundTripper) dialTLSHTTP2(network, addr string, _ *utls.Config) (net.Conn, error) {
//	return rt.dialTLS(context.Background(), network, addr)
//}
//
//func (rt *RoundTripper) getDialTLSAddr(req *http.Request) string {
//	host, port, err := net.SplitHostPort(req.URL.Host)
//	if err == nil {
//		return net.JoinHostPort(host, port)
//	}
//	return net.JoinHostPort(req.URL.Host, "443") // we can assume port is 443 at this point
//}
//
//func newRoundTripper(ja3, ua string, dialer ...proxy.ContextDialer) http.RoundTripper {
//	//ja3 := `771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-51-57-47-53-10,0-23-65281-10-11-35-16-5-51-43-13-45-28-21,29-23-24-25-256-257,0`
//	//ua := `Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:87.0) Gecko/20100101 Firefox/87.0`
//
//	//ja3 := `771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-21,29-23-24,0`
//	//ua := `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36`
//	if len(dialer) > 0 {
//		return &RoundTripper{
//			Dialer: dialer[0],
//
//			JA3:               ja3,
//			UserAgent:         ua,
//			Cookies:           nil,
//			cachedTransports:  make(map[string]http.RoundTripper),
//			cachedConnections: make(map[string]net.Conn),
//		}
//	}
//
//	return &RoundTripper{
//		Dialer: proxy.Direct,
//		JA3:               ja3,
//		UserAgent:         ua,
//		Cookies:           nil,
//		cachedTransports:  make(map[string]http.RoundTripper),
//		cachedConnections: make(map[string]net.Conn),
//	}
//}
